package cn.edu.fzu.homemaking.session;

import static cn.edu.fzu.homemaking.common.SessionConstant.*;
import static java.util.concurrent.TimeUnit.SECONDS;

import java.io.IOException;

import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

@Order(1)
@Component
public class UserSessionFilter implements Filter {

    private static final Logger                     log = LoggerFactory.getLogger(UserSessionFilter.class);

    private final LoadingCache<String, UserSession> cache;

    @Autowired
    public UserSessionFilter(@Qualifier("webApplicationContext") final WebApplicationContext webApplicationContext) {

        final ServletContext servletContext = webApplicationContext.getServletContext();
        CacheLoader<String, UserSession> loader = new CacheLoader<String, UserSession>() {
            @Override
            public UserSession load(String key) throws Exception {
                return new UserSession(servletContext, key);
            }
        };

        cache = CacheBuilder.newBuilder().expireAfterAccess(SESSION_TIMEOUT, SECONDS).build(loader);
    }


    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // do nothing
    }


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse rsp = (HttpServletResponse) response;

        String domain = req.getServerName();

        // 将 session id 写入 cookie, 如果是退出登录, 则删除 cookie
        Cookie cookie = getOrCreateSessionCookie(req);
        cookie.setDomain(domain);
        cookie.setPath(COOKIE_PATH);
        cookie.setMaxAge(SESSION_TIMEOUT);
        rsp.addCookie(cookie);

        String dSessionId = cookie.getValue();
        UserSession session = cache.getUnchecked(dSessionId);
        UserSessionRequest requestWrapper = new UserSessionRequest(req, session);
        chain.doFilter(requestWrapper, response);
    }


    @Override
    public void destroy() {
        // do nothing
    }


    // 从 web 端请求中获取 cookie, 如果没有就创建一个
    private static Cookie getOrCreateSessionCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        log.error("sessionId:" + request.getSession().getId());
        if (ArrayUtils.isNotEmpty(cookies)) {
            for (Cookie item : cookies) {
                log.error("cookie item:" + item);
                if (DSESSIONID.equals(item.getName())) {
                    return item;
                }
            }
        }
        String sessionId = request.getParameter(DSESSIONID);
        return new Cookie(DSESSIONID, StringUtils.isBlank(sessionId) ? request.getSession().getId() : sessionId);
    }

}
